﻿using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Diagnostics;

namespace Qreed.Windows.ComponentModel
{
    /// <summary>
    /// This class is used to display multiple <see cref="PropertyBagItem"/> instances of the property type in a property grid.
    /// </summary>
    /// <remarks>
    /// Altho the class definition has the <see cref="TypeConverter"/> attribute, the custom 
    /// type converter is applied via <see cref="PropertyBagItemDescriptor.Converter"/> and not
    /// via this attribute. It's only included for clearity.
    /// </remarks>
    [TypeConverter(typeof(PropertyBagExpandableItemConverter))]
    public class PropertyBagExpandableItem : PropertyBagItem
    {
        #region Construction

        /// <summary>
        /// Initializes a new instance of the <see cref="PropertyBagExpandableItem"/> class.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="displayName">The display name.</param>
        /// <param name="value">The value.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <param name="category">The category.</param>
        /// <param name="description">The description.</param>
        /// <param name="isReadOnly">if set to <c>true</c> [is read only].</param>
        /// <param name="isBrowsable">if set to <c>true</c> [is browsable].</param>
        /// <param name="type">The type.</param>
        internal PropertyBagExpandableItem(string name, string displayName, 
                                         object value, object defaultValue, 
                                         string category, string description, 
                                         bool isReadOnly, bool isBrowsable, Type type)
            : base(name, displayName, value, defaultValue, category, description, isReadOnly, isBrowsable, type)
        {
            TypeConverter = new PropertyBagExpandableItemConverter();
            Type = typeof(string);

            ChildType = type;
        }

        #endregion

        #region Properties

        private Type _childType;
        /// <summary>
        /// Gets or sets the type of the child.
        /// </summary>
        /// <value>The type of the child.</value>
        public Type ChildType
        {
            get { return this._childType; }
            set { this._childType = value; }
        }	

        private string _multipleValuesText;
        /// <summary>
        /// Gets or sets the multiple values text.
        /// </summary>
        /// <value>The multiple values text.</value>
        public string MultipleValuesText
        {
            get 
            {
                if (string.IsNullOrEmpty(this._multipleValuesText))
                    return "<multiple values>";
                
                return this._multipleValuesText; 
            }

            set { this._multipleValuesText = value; }
        }	

        private PropertyBagItemCollection _items = new PropertyBagItemCollection(null);
        /// <summary>
        /// Gets the items.
        /// </summary>
        /// <value>The items.</value>
        public PropertyBagItemCollection Items
        {
            get {return this._items;}
        }

        /// <summary>
        /// Gets or sets the property bag.
        /// </summary>
        /// <value>The property bag.</value>
        public override PropertyBag Bag
        {
            get
            {
                return base.Bag;
            }
            internal set
            {
                base.Bag = value;
                Items.Bag = value;
            }
        }

        /// <summary>
        /// Gets the property descriptor for this item.
        /// </summary>
        /// <param name="attributes">The attributes.</param>
        /// <returns>
        /// A property descriptor for this property bag item.
        /// </returns>
        public override PropertyDescriptor GetPropertyDescriptor(Attribute[] attributes)
        {
            return new PropertyBagExpandableItemDescriptor(this, attributes);
        }

        // internal bool InUpdate = false;

        protected override void SetValue(object value)
        {
            if (object.Equals(value, MultipleValuesText))
                return;

            value = Convert.ChangeType(value, ChildType);

            PropertyDescriptorCollection coll = Items.GetProperties(null);

            foreach (PropertyBagItemDescriptor p in coll)
                p.SetValue(null, value);
        }

        protected override object GetValue()
        {
            if (Items.Count == 0)
                throw (new ApplicationException("No properties"));

            object value = Items[0].Value;

            for (int i = 1; i < Items.Count; i++)
            {
                PropertyBagItem item = Items[i];

                if (!object.Equals(value, item.Value))
                {
                    return MultipleValuesText;
                }
            }

            if (value == null) // This will ensure that the item can always be expanded if there are child elements available.
                value = "";

            return value;
        }

        #endregion
    }
}
